#pragma once
#include "msg_type.h"
#include "google/protobuf/text_format.h"
#include <string>
#include <map>
#include <regex>
#include <mutex>
#include <shared_mutex>
#include <iostream>
#include <fstream>
#include <functional>
#include <chrono>
#include "log4z.h"
#include "export.h"
#include "json.hpp"
using namespace zsummer::log4z;
#define GET_ORIGIN_DATA(pb_type,...) ShareData::GetInstance().GetImplDataPtr(#pb_type,##__VA_ARGS__ )->GetOriginPtr()
#define GET_SHARE_DATA(pb_type,...) ShareData::GetInstance().GetImplDataPtr(#pb_type,##__VA_ARGS__ )->GetCopyDataPtr<pb_type>()
#define GET_SHARE_DATA_CONTAINER(pb_type,...) ShareData::GetInstance().GetImplDataPtr(#pb_type,##__VA_ARGS__ )
class DEMO_EXPORT Setting
{
public:
	static Setting& GetInstance()
	{
		static Setting set;
		return set;
	}
	std::string GetIdentify() {
		return set_["identify"];
	}
	std::string GetParam(const char* _key) {
		if (set_.contains(_key))
		{
			return set_[_key].get<std::string>();
		}
		return "null";
	}
	static int64_t NowToMillseconds()
	{
		using namespace std;
		chrono::time_point<chrono::system_clock, chrono::milliseconds> tp = \
			chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
		auto tmp = chrono::duration_cast<chrono::milliseconds>(tp.time_since_epoch());
		return tmp.count();
	}
	static 	std::string MillToTime(int64_t milli)
	{
		char buf[128] = { 0 };
		int64_t tmp = milli + (int64_t)8 * 60 * 60 * 1000;//此处转化为东八区北京时间，如果是其它时区需要按需求修改
		auto mTime = std::chrono::milliseconds(tmp);
		auto tp = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>(mTime);
		auto tt = std::chrono::system_clock::to_time_t(tp);
		std::tm* now = std::gmtime(&tt);
		snprintf(buf,128, "%04d-%02d-%02d %02d:%02d:%02d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
		return buf;
	}
	static google::protobuf::Message* CreateMessage(std::string name)
	{
		using namespace google::protobuf;
		Message* message = nullptr;
		const Descriptor* descriptor = DescriptorPool::generated_pool()->\
			FindMessageTypeByName("msgType." + name);
		if (descriptor)
		{
			const Message* prototype = MessageFactory::generated_factory()->\
				GetPrototype(descriptor);
			if (prototype)
			{
				message = prototype->New();
			}
		}
		return message;
	}
	static const google::protobuf::EnumDescriptor* CreateEnum(std::string name)
	{
		using namespace google::protobuf;
		const EnumDescriptor* message = nullptr;
		const EnumDescriptor* descriptor = DescriptorPool::generated_pool()->\
			FindEnumTypeByName("msgType." + name);
		if (descriptor)
		{
			message = descriptor;
		}
		return message;
	}
private:
	//加载主配置文件
	Setting() {
		try
		{
			std::ifstream t("config/plugin.json");
			std::stringstream buffer;
			buffer << t.rdbuf();
			std::string contents(buffer.str());
			t.close();
			set_ = nlohmann::json::parse(contents);
		}
		catch (const std::exception&)
		{
			set_["identify"] = "undefined";
		}
	}
	nlohmann::json set_;
};
//定义共享数据基类
class pb_data_impl
{
public:
	pb_data_impl(std::string pb_name, std::string pb_id = "") :
		name_(pb_name),
		id_(pb_id),
		stamp_(-1),
		p_msg_(nullptr)
	{

	}
	bool init()
	{
		//创建新Message
		p_msg_ = create_message(name_);
		if (p_msg_ == nullptr)
		{
			LOGFMTE("error create [%s]", name_.c_str());
			return false;
		}
		return true;
	}
	virtual~pb_data_impl()
	{
		if (p_msg_)
		{
			p_msg_->Clear();
			delete(p_msg_);
		}
	}
	void UpdateStamp()
	{
		stamp_ = Setting::NowToMillseconds();
	}
	int64_t GetStamp()
	{
		return stamp_;
	}
	google::protobuf::Message* GetOriginPtr()
	{
		return p_msg_;
	}
	void CommitData()
	{
		/*string topic = AuvTool::GetIdentifyName() + "/data/" + name_;
		if (id_ != "") topic += "/" + id_;
		p_msg_->SerializeToString(&ser_buf_);
		GET_DMC_HANDLE.PublishData(topic, ser_buf_.c_str(), ser_buf_.length());*/
	}
	void DebugData()
	{
		/*string topic = AuvTool::GetIdentifyName() + "/debug/" + name_;
		if (id_ != "") topic += "/" + id_;
		string debug_buf_ = p_msg_->DebugString();
		GET_DMC_HANDLE.PublishData(topic, debug_buf_.c_str(), debug_buf_.length());*/
	}
	//使用读写锁  写锁  非阻塞
	void WLock()
	{
		rwlock_.lock();
	}
	//使用读写锁  解锁
	void WrUnLock()
	{
		rwlock_.unlock();
	}
	//返回一个对象
	//当返回对象失效后解锁
	template<typename T>
	const std::shared_ptr<T> GetCopyDataPtr()
	{
		std::shared_ptr<T> sp(dynamic_cast<T*>(p_msg_), std::bind(&pb_data_impl::WrUnLock, this));
		rwlock_.lock();
		return sp;
	}
private:
	google::protobuf::Message* create_message(std::string& name)
	{
		using namespace google::protobuf;
		Message* message = nullptr;
		const Descriptor* descriptor = DescriptorPool::generated_pool()->\
			FindMessageTypeByName("msgType." + name);
		if (descriptor)
		{
			const Message* prototype = MessageFactory::generated_factory()->\
				GetPrototype(descriptor);
			if (prototype)
			{
				message = prototype->New();
			}
		}
		return message;
	}
	std::string name_;
	std::string id_;
	std::string ser_buf_;
	int64_t stamp_;
	//QReadWriteLock rwlock_;
	std::mutex rwlock_;
	//std::shared_timed_mutex rwlock_;
	google::protobuf::Message* p_msg_;
};
class pb_data_desp
{
public:
	~pb_data_desp()
	{
		LOGFMTD("%s deleter",pb_type.c_str());
	}
	google::protobuf::Message* ptr{ nullptr };
	std::string pb_type;
	std::string identify;
	std::vector<std::string> pb_item;
};
class DEMO_EXPORT ShareData
{
public:
	static ShareData& GetInstance()
	{
		static ShareData instance;
		return instance;
	}
	//导出全部proto类型数据
	std::map<std::string, std::vector<std::string>>& ExportDesignData()
	{
		return proto_map_;
	}
	int size()
	{
		return map_.size();
	}
	//导出当前有效的proto数据
	std::vector<pb_data_desp*> ExportValidData()
	{
		std::vector<pb_data_desp*> tmp;
		std::lock_guard<std::mutex> lock(lock_);
		for (auto it = map_.begin(); it != map_.end(); it++)
		{
			auto t = std::shared_ptr<pb_data_desp>(new pb_data_desp);
			t->pb_type = std::get<0>(it->first);
			t->identify = std::get<1>(it->first);
			t->ptr = it->second->GetOriginPtr();
			if (proto_map_.find(t->pb_type) != proto_map_.end())
			{
				t->pb_item = proto_map_[t->pb_type];
			}
			tmp.push_back(t.get());
		}
		return tmp;
	}
	//获取基类数据指针
	pb_data_impl* GetImplDataPtr(std::string name, std::string id = "")
	{
		pb_data_impl* ptr = nullptr;
		lock_.lock();
		if (map_.find(make_tuple(name, id)) == map_.end())//新建对象
		{
			ptr = new pb_data_impl(name, id);
			if (ptr->init())
				map_.insert(make_pair(make_tuple(name, id), ptr));
		}
		else
		{
			ptr = map_[make_tuple(name, id)];
		}
		lock_.unlock();
		return ptr;
	}
	void MqttCallback(std::string _topic,const void* _pdata,int32_t _len)
	{
		//if (_pdata &&_len > 0)
		//{
		//	std::smatch result;
		//	if (std::regex_match(_topic, result, *p_data_) && result.size() == 3)
		//	{
		//		auto ptr = GetImplDataPtr(result.str(1), result.str(2));
		//		//创建/获取数据
		//		if (ptr)
		//		{
		//			////按照10HZ更新频率算,超过100ms，强制更新数据
		//			//if (AuvTool::NowToMillseconds() - ptr->GetStamp() > 100)
		//			//	ptr->WLock();
		//			//else
		//			//	ptr->TryWLock();
		//			ptr->WLock();
		//			ptr->GetOriginPtr()->ParseFromArray(_pdata, _len);
		//			//qDebug() << "--" << ptr->GetOriginPtr()->DebugString().c_str();
		//			ptr->UpdateStamp();
		//			ptr->WrUnLock();
		//		}
		//	}
		//}
	}
private:
	ShareData(std::string space = "msgType")
	{
		p_data_ = new std::regex(".*/data/(pb_[0-9a-zA-Z_]+)/{0,1}(.*)");
		using namespace google::protobuf;
		auto tp = DescriptorPool::generated_pool()->FindMessageTypeByName("msgType.typeInit");
		if (tp)
		{
			auto f = tp->file();
			for (int i = 0; i < f->message_type_count(); i++)
			{
				auto msg_type = f->message_type(i);
				vector<string> tmp;
				for (int j = 0; j < msg_type->field_count(); j++)
				{
					tmp.push_back(msg_type->field(j)->name());
				}
				proto_map_.insert(make_pair(msg_type->name(), tmp));
			}
		}
	}
	ShareData(const ShareData&) = delete;
	std::map<std::tuple<std::string, std::string>, pb_data_impl*> map_;
	std::string  space_;
	std::regex* p_data_;
	std::mutex lock_;
	std::map<std::string, std::vector<std::string>> proto_map_;
};

